﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CarbonExchange.AmeeQuery;
using CarbonExchange.Dal;

namespace CarbonExchange.Bll
{
    public class UserSectionFactory : FactoryBase<UserSection>
    {
        public UserSectionFactory() : base() { }

        public UserSectionFactory(IAmeeCommand ameeCommand) : base(ameeCommand) { }

        public UserSectionFactory(Context dalContext) : base(dalContext) { }

        public UserSectionFactory(IAmeeCommand ameeCommand, Context dalContext) : base(ameeCommand, dalContext) { }

        protected override void MarkItemForDeletion(UserSection item)
        {
            var tmp = item.Convert(DalContext);
            tmp.Deleted = true;
        }

        protected override void Validate(IQueryable<UserSection> items, CarbonExchange.Bll.Exceptions.ValidationException exp)
        {
            items.Validate(DalContext, exp);
        }

        protected override void PopulateDataChanges(UserSection item, object dataItem)
        {
            var tmp = dataItem as Dal.UserSection;
            if (item.Id == 0)
            {
                item.Id = tmp.Id;
                item.SectionName = tmp.Section.Name;
                item.Created = tmp.Created.ToLocalTime();
                var tmpFootprints = DalContext.AnswerItems.Where(x => x.Answer.Question.SectionId == tmp.SectionId && x.Answer.AuditId == tmp.AuditId).Where(x => x.Footprint.HasValue).Select(x => x.Footprint.Value).ToList();
                if(tmpFootprints.Count() > 0)
                {
                    item.Footprint = tmpFootprints.Sum() * 12;
                }
                else
                {
                    item.Footprint = 0m;
                }
                item.AuditDate = tmp.Audit.EndDate;
            }
        }

        protected override object GetDataItemForUpdate(UserSection item)
        {
            return item.Convert(DalContext);
        }

        private IQueryable<JoinHelper> GetSelection()
        {
            //NB Multiplyed by 12 to convert to anual footprint
            return DalContext.UserSections.Where(x => !x.Deleted && !x.Audit.Deleted)
                .Join(
                    DalContext.Sections.Where(x => !x.Deleted).OrderBy(x => x.Sequence),
                    x => x.SectionId,
                    y => y.Id, 
                    (x, y) => new JoinHelper() 
                        { 
                                UserSection = x, 
                                Audit = x.Audit,
                                SectionName = y.Name, 
                                Footprint = DalContext.AnswerItems.Where(z => z.Answer.Question.SectionId == x.SectionId && z.Answer.AuditId == x.AuditId).Where(z => z.Footprint.HasValue).Count() > 0 ? DalContext.AnswerItems.Where(z => z.Answer.Question.SectionId == x.SectionId && z.Answer.AuditId == x.AuditId).Where(z => z.Footprint.HasValue).Sum(z => z.Footprint.Value) * 12 : 0m}
                    );
        }

        public UserSection GetById(int id)
        {
            return GetSelection().Where(x => x.UserSection.Id == id).SingleOrDefault().Convert();
        }

        public List<UserSection> GetAllByAuditId(int auditId)
        {
            return GetSelection().Where(x => x.UserSection.AuditId == auditId).Convert().ToList();
        }

        internal class JoinHelper
        {
            internal Dal.UserSection UserSection{get;set;}
            internal string SectionName{get;set;}
            internal decimal Footprint { get; set; }
            internal Dal.Audit Audit { get; set; }

        }

        public List<UserSection> GetAllByUserId(int userId)
        {
            return GetSelection().Where(x => x.UserSection.Audit.UserId == userId).Convert().ToList();
        }

        public List<UserSectionAverage> GetAveragesBySiteId(int siteId)
        {
            //ToDo: add in site id to the audit because a user can belong to many sites
            //var tmp = GetSelection().Where(x => x.UserSection.Completed && x.Audit.EndDate <= endDate.AddYears(1) && x.Audit.EndDate >= endDate.AddYears(-1) && (x.Audit.AcmsUser.SiteId ?? siteId) == siteId);
            //return tmp.GroupBy(x => x.UserSection.Id).Select(x => new UserSectionAverage() { AuditDate = endDate, SectionId = x.First().UserSection.SectionId, SectionName = x.First().SectionName, Footprint = x.Average(y => y.Footprint) }).ToList(); 

            //get site users
            var tmp = GetSelection().Where(x => (x.Audit.AcmsUser.SiteId ?? siteId) == siteId);
            //get completed sections
            tmp = tmp.Where(x => x.UserSection.Completed);
            return tmp.GroupBy(x => x.UserSection.SectionId).Select(x => new UserSectionAverage() { Footprint = x.Average(y => y.Footprint), SectionId = x.First().UserSection.SectionId, SectionName = x.First().SectionName }).ToList();
        }
    }

    public static class UserSectionFactoryConverter
    {
        internal static UserSection Convert(this UserSectionFactory.JoinHelper item)
        {
            return ConvertItem(item);
        }

        internal static IQueryable<UserSection> Convert(this IQueryable<UserSectionFactory.JoinHelper> item)
        {
            return item.Select(x => ConvertItem(x));
        }

        private static UserSection ConvertItem(UserSectionFactory.JoinHelper item)
        {
            if (item != null && item.UserSection != null)
            {
                return new UserSection()
                {
                    Id = item.UserSection.Id,
                    AuditId = item.UserSection.AuditId,
                    AuditDate = item.Audit.EndDate,
                    SectionId = item.UserSection.SectionId,
                    SectionName = item.SectionName,
                    Completed = item.UserSection.Completed,
                    Footprint = item.Footprint,
                    Created = DateTime.SpecifyKind(item.UserSection.Created, DateTimeKind.Utc).ToLocalTime()
                };
            }
            else
            {
                return null;
            }
        }

        public static Dal.UserSection Convert(this UserSection item, Dal.Context context)
        {
            return ConvertItem(item, context);
        }

        public static IQueryable<Dal.UserSection> Convert(this IQueryable<UserSection> item, Dal.Context context)
        {
            return item.Select(x => ConvertItem(x, context));
        }

        private static Dal.UserSection ConvertItem(UserSection item, Dal.Context context)
        {
            if (item != null)
            {
                Dal.UserSection dataItem = null;
                if (item.Id > 0)
                {
                    dataItem = context.UserSections.Where(x => x.Id == item.Id).Single();
                }
                else
                {
                    dataItem = new CarbonExchange.Dal.UserSection();
                    dataItem.Created = DateTime.UtcNow;
                    context.UserSections.InsertOnSubmit(dataItem);
                }
                dataItem.AuditId = item.AuditId;
                dataItem.Completed = item.Completed;
                dataItem.SectionId = item.SectionId;
                return dataItem;
            }
            else
            {
                return null;
            }
        }

        internal static void Validate(this IQueryable<UserSection> items, Dal.Context context, CarbonExchange.Bll.Exceptions.ValidationException e)
        {
            foreach (var item in items)
            {
                item.Validate(context, e);
            }
        }

        internal static void Validate(this UserSection item, Dal.Context context, CarbonExchange.Bll.Exceptions.ValidationException e)
        {
        }

    }
}
